package com.jiang.test;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ConditionProducerAndConsumer {

	public static void main(String[] args) {
		DataBuf<String> buffer = new DataBuf<>(5);
		for(int i=0;i<10;i++) {
			int temp = i;
			new Thread(()->{
				buffer.put("生日快乐"+temp);
				try {
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			},"数据生产者-"+i).start();
			new Thread(()->{
				System.out.println(buffer.get());
				try {
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			},"数据消费者-"+i).start();
		}
	}
	
}

class DataBuf<T>{
	
	private static final Integer MAX_SIZE = 5; // 默认的数组容量
	private Lock lock = new ReentrantLock();
	private Condition putCondition = lock.newCondition(); // 进行线程通信的生产者condition
	private Condition getCondition = lock.newCondition(); // 进行线程通信的消费者condition
	private T[] datas = null;  // 保存数据的数组
	private int count = 0; // 保存数组中数据的数据量大小
	private int putIndex=0;// 生产者索引
    private int getIndex=0; // 消费者索引
    // 构造函数
    @SuppressWarnings("unchecked")
	public DataBuf(){
    	this.datas = (T[]) new Object[MAX_SIZE];
    }
    // 有参数构造函数
    @SuppressWarnings("unchecked")
	public DataBuf(int size){
    	if(size>0) {
    		this.datas = (T[]) new Object[size];
    	}else {
    		this.datas = (T[]) new Object[MAX_SIZE];
    	}
    }
    
    // 生产数据
    public void put(T data) {
    	this.lock.lock();
    	try {
    		if(this.count==this.datas.length) {
    			// 满了不能生产了
    			System.out.println("生产容器已经满了,不能生产了，等待消费者消费!");
    			putCondition.await();
    		}
    		this.datas[this.putIndex++] = data;
    		System.out.println("当前线程:"+Thread.currentThread().getName()+"存储数据为:"+data);
    		if(this.putIndex==this.datas.length) {
    			this.putIndex = 0;
    		}
    		this.count++;
    		// 唤醒消费者
    		this.getCondition.signal();
    	}catch(Exception e) {
    		e.printStackTrace();
    	}finally {
    		this.lock.unlock();
    	}
    }
    
    // 消费数据
    public T get() {
    	this.lock.lock();
    	T returnVal = null;
    	try {
    		if(this.count==0) {
    			// 空了不能消费了
    			System.out.println("消费容器已经空了,不能消费了，等待生产者生产!");
    			getCondition.await(); // 消费者等待
    		}
    		returnVal = this.datas[getIndex++];
    		if(this.getIndex==this.datas.length) {
    			this.getIndex = 0;
    		}
    		this.count--;
    		// 唤醒生产者
    		this.putCondition.signal();
    	}catch(Exception e) {
    		e.printStackTrace();
    	}finally {
    		this.lock.unlock();
    	}
    	return returnVal;
    }
    
}

